package cn.keniykey.mc.viewlibrary.packet;

import java.util.Arrays;
import java.util.List;

import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

import cn.keniykey.mc.viewlibrary.channel.AbChannelUtil;
import cn.keniykey.mc.viewlibrary.container.api.EContainerType;
import cn.keniykey.mc.viewlibrary.packet.api.AbPacket;
import cn.keniykey.mc.viewlibrary.packet.api.IPacketDispatch;
import cn.keniykey.mc.viewlibrary.packet.api.PacketItemName;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowClick;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowClose;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowCloseDispatch;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowDataDispatch;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowItemsDispatch;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowOpenDispatch;
import cn.keniykey.mc.viewlibrary.packet.api.PacketWindowSetSlotDispatch;
import cn.keniykey.mc.viewlibrary.reflection.ReflectionMethod;
import cn.keniykey.mc.viewlibrary.reflection.ReflectionUtil;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.ChatComponentText;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.PacketPlayInCloseWindow;
import net.minecraft.network.protocol.game.PacketPlayInItemName;
import net.minecraft.network.protocol.game.PacketPlayInWindowClick;
import net.minecraft.network.protocol.game.PacketPlayOutCloseWindow;
import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow;
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
import net.minecraft.network.protocol.game.PacketPlayOutWindowData;
import net.minecraft.network.protocol.game.PacketPlayOutWindowItems;
import net.minecraft.world.inventory.Containers;
import net.minecraft.world.inventory.InventoryClickType;

public class PacketUtilV1_17_1 extends AbPacketUtil {
	private final List<InventoryClickType> list_modes = Arrays.asList(InventoryClickType.values());
	
	private final ReflectionMethod method_bukkit_itemstack_asnmscopy;
	private final net.minecraft.world.item.ItemStack obj_nm_itemstack_emptyitem;
	
	PacketUtilV1_17_1() {
		this.method_bukkit_itemstack_asnmscopy = ReflectionUtil.findReflectionClass("cb,inventory.CraftItemStack").findMethodByName("asNMSCopy");
		this.obj_nm_itemstack_emptyitem = (net.minecraft.world.item.ItemStack)this.method_bukkit_itemstack_asnmscopy.invoke(new ItemStack(Material.AIR));
	}

	@Override
	public void dispatchPacket(Player player, IPacketDispatch packet,boolean cache) {
		Object obj_packet = packet.getCacheReflectionPacket();
		if(obj_packet == null || !(obj_packet instanceof Packet)) {
			if(packet instanceof PacketWindowCloseDispatch) {
				final PacketWindowCloseDispatch pack = (PacketWindowCloseDispatch)packet;
				obj_packet = new PacketPlayOutCloseWindow(pack.getID());
			}else if(packet instanceof PacketWindowDataDispatch) {
				final PacketWindowDataDispatch pack = (PacketWindowDataDispatch)packet;
				obj_packet = new PacketPlayOutWindowData(pack.getID(), pack.getProperty(), pack.getValue());
			}else if(packet instanceof PacketWindowOpenDispatch) {
				final PacketWindowOpenDispatch pack = (PacketWindowOpenDispatch)packet;
				obj_packet = new PacketPlayOutOpenWindow(pack.getID(), this.coverContainers(pack.getContainerType()), new ChatComponentText(pack.getTitle()));
			}else if(packet instanceof PacketWindowSetSlotDispatch) {
				final PacketWindowSetSlotDispatch pack = (PacketWindowSetSlotDispatch)packet;
				obj_packet = new PacketPlayOutSetSlot(pack.getID(), pack.getID(), pack.getSlot(), this.toNmsItemStack(pack.getItemStack()));
			}else if(packet instanceof PacketWindowItemsDispatch) {
				final PacketWindowItemsDispatch pack = (PacketWindowItemsDispatch)packet;
				final net.minecraft.world.item.ItemStack[] array_nm_items = new net.minecraft.world.item.ItemStack[pack.getItems().size()];
				int index = 0;
				for(final ItemStack item : pack.getItems()) {
					array_nm_items[index] = this.toNmsItemStack(item);
					index++;
				}
				obj_packet = new PacketPlayOutWindowItems(pack.getID(), pack.getID(), NonNullList.a(this.obj_nm_itemstack_emptyitem, array_nm_items), this.obj_nm_itemstack_emptyitem);
//				for(int dex = 0; dex < array_nm_items.length; dex++) array_nm_items[dex] = null;
			}else {
				throw new RuntimeException("Unknown AbPacketWindow(未知发包类型)");
			}
			if(cache) packet.setCacheReflectionPacket(obj_packet);
		}
		AbChannelUtil.getUtil().sendPacket(player, obj_packet);
	}
	private Containers<?> coverContainers(EContainerType type) {
		switch(type) {
		case GENERIC_1X9: return Containers.a;
		case GENERIC_2X9: return Containers.b;
		case GENERIC_3X9: return Containers.c;
		case GENERIC_4X9: return Containers.d;
		case GENERIC_5X9: return Containers.e;
		case GENERIC_6X9: return Containers.f;
		case GENERIC_3X3: return Containers.g;
		case ANVIL: return Containers.h;
		case CRAFTING_TABLE: return Containers.l;
		case ENCHANTMENT_TABLE: return Containers.m;
		case HOPPER: return Containers.p;
		case LOOM: return Containers.r;
		case STONECUTTER: return Containers.x;
		}
		throw new RuntimeException("Unknown EContainerType(在当前版本属于未知界面类型)");
	}
	private net.minecraft.world.item.ItemStack toNmsItemStack(ItemStack item) {
		if(item == null || item.getType().equals(Material.AIR)) return this.obj_nm_itemstack_emptyitem;
		return (net.minecraft.world.item.ItemStack)this.method_bukkit_itemstack_asnmscopy.invoke(item);
	}

	@Override
	public AbPacket coverPacket(Object nmspacket, int windowid) {
		if(nmspacket instanceof PacketPlayInCloseWindow) {
			final int id = ((PacketPlayInCloseWindow)nmspacket).b();
			if(windowid != id) return null;
			return new PacketWindowClose(id);
		}
		if(nmspacket instanceof PacketPlayInWindowClick) {
			final int id = ((PacketPlayInWindowClick)nmspacket).b();
			if(windowid != id) return null;
			final int mode = list_modes.indexOf(((PacketPlayInWindowClick)nmspacket).g());
			final int button = ((PacketPlayInWindowClick)nmspacket).d();
			final int slot = ((PacketPlayInWindowClick)nmspacket).c();
			return new PacketWindowClick(windowid, mode, button, slot);
		}
		if(nmspacket instanceof PacketPlayInItemName) {
			final String name = ((PacketPlayInItemName)nmspacket).b();
			return new PacketItemName(name);
		}
		return null;
	}
}